﻿﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;


namespace MapSurface.WidgetSurface
{
    public class WindowResizer
    {
        private BorderElement target = null;
        public UIElement MainCanvas;

        private bool resizeRight = false;
        private bool resizeLeft = false;
        private bool resizeUp = false;
        private bool resizeDown = false;
        private bool _canResize = false;
        public delegate void DisplayProperty(object target);
        public DisplayProperty displayProp;
        public bool CanResize
        {
            get { return _canResize; }
            set { _canResize = value; }
        }

        private Dictionary<UIElement, short> leftElements = new Dictionary<UIElement, short>();
        private Dictionary<UIElement, short> rightElements = new Dictionary<UIElement, short>();
        private Dictionary<UIElement, short> upElements = new Dictionary<UIElement, short>();
        private Dictionary<UIElement, short> downElements = new Dictionary<UIElement, short>();

        private Point resizePoint = new Point();
        private Size resizeSize = new Size();
        private Thickness margin = new Thickness(0, 0, 0, 0);
        private Point p = new Point();
        private delegate void RefreshDelegate();
        private delegate void RefreshDelegatePoint(Point p);
        Contact uielementControlContact;


        public WindowResizer(BorderElement target)
        {
            this.target = target;
            if (target == null)
            {
                throw new Exception("Invalid Window handle");
            }
        }

        #region add resize components
        public void connectMouseHandlers(UIElement element)
        {
            element.AddHandler(Contacts.ContactDownEvent, new ContactEventHandler(element_ContactDown));
            element.AddHandler(Contacts.ContactChangedEvent, new ContactEventHandler(element_ContactChanded));
            element.AddHandler(Contacts.ContactLeaveEvent, new ContactEventHandler(element_ContactLeaveHandler));
        }

        public void deConnectMouseHandlers(UIElement element)
        {
            element.RemoveHandler(Contacts.ContactDownEvent, new ContactEventHandler(element_ContactDown));
            element.RemoveHandler(Contacts.ContactChangedEvent, new ContactEventHandler(element_ContactChanded));
            element.RemoveHandler(Contacts.ContactLeaveEvent, new ContactEventHandler(element_ContactLeaveHandler));
        }

        public void addResizerRight(UIElement element)
        {
            connectMouseHandlers(element);
            rightElements.Add(element, 0);
        }

        public void addResizerLeft(UIElement element)
        {
            connectMouseHandlers(element);
            leftElements.Add(element, 0);
        }

        public void addResizerUp(UIElement element)
        {
            connectMouseHandlers(element);
            upElements.Add(element, 0);
        }

        public void addResizerDown(UIElement element)
        {
            connectMouseHandlers(element);
            downElements.Add(element, 0);
        }

        public void addResizerRightDown(UIElement element)
        {
            connectMouseHandlers(element);
            rightElements.Add(element, 0);
            downElements.Add(element, 0);
        }

        public void addResizerLeftDown(UIElement element)
        {
         //   connectMouseHandlers(element);
         //   leftElements.Add(element, 0);
         //   downElements.Add(element, 0);
        }

        public void addResizerRightUp(UIElement element)
        {
            //connectMouseHandlers(element);
            //rightElements.Add(element, 0);
            //upElements.Add(element, 0);
        }

        public void addResizerLeftUp(UIElement element)
        {
            connectMouseHandlers(element);
            leftElements.Add(element, 0);
            upElements.Add(element, 0);
        }
        #endregion

        #region resize handlers
        private void element_ContactDown(object sender, ContactEventArgs e)
        {
            if (CanResize)
            {
                resizePoint = e.Contact.GetCenterPosition(MainCanvas);
                resizeSize = target.RenderSize;
                uielementControlContact = e.Contact;

                #region updateResizeDirection
                UIElement sourceSender = (UIElement)sender;
                if (leftElements.ContainsKey(sourceSender))
                {
                    resizeLeft = true;
                }
                if (rightElements.ContainsKey(sourceSender))
                {
                    resizeRight = true;
                }
                if (upElements.ContainsKey(sourceSender))
                {
                    resizeUp = true;
                }
                if (downElements.ContainsKey(sourceSender))
                {
                    resizeDown = true;
                }
                #endregion
            }
            e.Handled = true;
        }
        private void element_ContactChanded(object sender, ContactEventArgs e)
        {
            if (CanResize && uielementControlContact != null)
            {
                UIElement sourceSender = (UIElement)sender;
                Point currentContactPoint = uielementControlContact.GetCenterPosition(MainCanvas);
                // Get the change between the controlling contact point and
                // the changed contact point.  
                double deltaX = currentContactPoint.X - resizePoint.X;
                double deltaY = currentContactPoint.Y - resizePoint.Y;
                double dou = e.Contact.GetOrientation(MainCanvas);
                if(dou<=135 && 45<=dou)
                {
                    //deltaX = deltaX * (-1);
                    //deltaY = deltaY * (-1);
                }
                #region Update Size
                if ( target.Content.Children.Count > 0)
                {
                    if (this.target.Height.CompareTo(Double.NaN) == 0 && this.target.RenderSize.Height != 0)
                    {

                        this.target.Height = this.target.RenderSize.Height;
                        this.target.Width = this.target.RenderSize.Width;
                        ((FrameworkElement)target.Content.Children[0]).Height = ((FrameworkElement)target.Content.Children[0]).RenderSize.Height;
                        ((FrameworkElement)target.Content.Children[0]).Width = ((FrameworkElement)target.Content.Children[0]).RenderSize.Width;

                    }
                    if (((FrameworkElement)target.Content.Children[0]).Width == 0)
                    {
                        ((FrameworkElement)target.Content.Children[0]).Width = 30;
                        this.target.Width = this.target.RenderSize.Width;
                    }
                    if (((FrameworkElement)target.Content.Children[0]).Height == 0)
                    {
                        ((FrameworkElement)target.Content.Children[0]).Height = 30;
                        this.target.Height = this.target.RenderSize.Height;
                    }
                }
                if (resizeRight)
                {
                    if (target.Width + deltaX > 30 && ((FrameworkElement)target.Content.Children[0]).Width+deltaX>30)
                    {
                        if (target.Content.Children.Count > 0)
                            ((FrameworkElement)target.Content.Children[0]).Width += deltaX;
                        target.Width = target.Width + deltaX;
                        target.Content.Width += deltaX;
                        target.MaxWidth += deltaX;
                        //target.Margin = new Thickness(target.Margin.Left, target.Margin.Top, target.Margin.Right - deltaX, target.Margin.Bottom);
                    }
                }

                if (resizeDown)
                {
                    if (target.Height + deltaY > 30 && ((FrameworkElement)target.Content.Children[0]).Height+deltaY>30)
                    {
                        if (target.Content.Children.Count > 0)
                            ((FrameworkElement)target.Content.Children[0]).Height += deltaY;
                        target.Height += deltaY;
                        target.Content.Height += deltaY;
                        target.MaxHeight += deltaY;
                        //target.Margin = new Thickness(target.Margin.Left, target.Margin.Top, target.Margin.Right, target.Margin.Bottom - deltaY);

                    }
                }

                if (resizeLeft)
                {
                    if (target.Width - deltaX > 30 && ((FrameworkElement)target.Content.Children[0]).Width-deltaX>20)
                    {
                        if (target.Content.Children.Count > 0)
                            ((FrameworkElement)target.Content.Children[0]).Width -= deltaX;
                        target.Width -= deltaX;
                        target.Content.Width -= deltaX;
                        target.MaxWidth += deltaX;
                        //target.Margin = new Thickness(target.Margin.Left + deltaX, target.Margin.Top, target.Margin.Right, target.Margin.Bottom);

                    }
                }

                if (resizeUp)
                {
                    if (target.Height - deltaY > 30 && ((FrameworkElement)target.Content.Children[0]).Height-deltaY>30)
                    {
                        if (target.Content.Children.Count > 0)
                            ((FrameworkElement)target.Content.Children[0]).Height -= deltaY;
                        target.Height -= deltaY;
                        target.Content.Height -= deltaY;
                        //target.Margin = new Thickness(target.Margin.Left, target.Margin.Top + deltaY, target.Margin.Right, target.Margin.Bottom);


                    }
                }
                if (target.Content.Children.Count > 0)
                    displayProp(target.Content.Children[0]);
                #endregion
                e.Handled = true;
            }


        }
        private void element_ContactLeaveHandler(object sender, ContactEventArgs e)
        {
            if (CanResize)
            {
                resizeRight = false;
                resizeLeft = false;
                resizeUp = false;
                resizeDown = false;
                uielementControlContact = null;
                e.Handled = true;
            }
        }

        #region updates
        private void updateSize()
        {

            if (CanResize)
            {
                if (this.target.Height.CompareTo(Double.NaN) == 0 && this.target.RenderSize.Height != 0)
                {

                    this.target.Height = this.target.RenderSize.Height;
                    this.target.Width = this.target.RenderSize.Width;
                }

                if (resizeRight)
                {
                    if (target.Width - (resizePoint.X - p.X) > 30)
                        target.Width = target.Width - (resizePoint.X - p.X);
                    //else target.Width = 31;
                }

                if (resizeDown)
                {
                    if (target.Height - (resizePoint.Y - p.Y) > 30)
                        target.Height = target.Height - (resizePoint.Y - p.Y);
                    //else target.Height = 31;
                }

                if (resizeLeft)
                {
                    if (target.Width + (resizePoint.X - p.X) > 30)
                        target.Width = target.Width + (resizePoint.X - p.X);
                    //else target.Width = 31;
                }

                if (resizeUp)
                {
                    if (target.Height + (resizePoint.Y - p.Y) > 30)
                        target.Height = target.Height + (resizePoint.Y - p.Y);
                    //else target.Height = 31;
                }
                displayProp(target);
            }
        }
        private void updateMouseDown()
        {
            {
                resizeRight = false;
                resizeLeft = false;
                resizeUp = false;
                resizeDown = false;
            }
        }
        private void updateSizeLoop()
        {
            try
            {
                while (resizeDown || resizeLeft || resizeRight || resizeUp)
                {
                    target.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new RefreshDelegate(updateSize));
                    target.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new RefreshDelegate(updateMouseDown));
                    Thread.Sleep(20);
                }

                target.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new RefreshDelegate(setArrowCursor));
            }
            catch (Exception)
            {
            }
        }

        #endregion
        #endregion

        #region cursor updates

        private void setWECursor(object sender, ContactEventArgs e)
        {
            target.Cursor = Cursors.SizeWE;
        }

        private void setNSCursor(object sender, ContactEventArgs e)
        {
            target.Cursor = Cursors.SizeNS;
        }

        private void setNESWCursor(object sender, ContactEventArgs e)
        {
            target.Cursor = Cursors.SizeNESW;
        }

        private void setNWSECursor(object sender, ContactEventArgs e)
        {
            target.Cursor = Cursors.SizeNWSE;
        }

        private void setArrowCursor(object sender, ContactEventArgs e)
        {
            updateMouseDown();
            e.Handled = true;
        }

        private void setArrowCursor()
        {
            target.Cursor = Cursors.Arrow;
        }
        #endregion
        public Object getAttribute(Object element, string attibuteName)
        {
            try
            {
                object o = null;
                Type type = element.GetType();
                PropertyInfo pi = type.GetProperty(attibuteName);
                if (pi != null)
                {
                    MethodInfo[] mi = pi.GetAccessors();
                    object[] param = null;
                    if (mi != null)
                        o = pi.GetValue(element, param);
                    return o;

                }
            }
            catch (Exception)
            {
                //;
            }
            return null;
        }


    }

    public class WindowMove
    {
        Contact uielementControlContact;
        Point lastPoint;
        public UIElement MainCanvas;
        private UIElement parent = null;

        public bool CanMove = false;

        public WindowMove(UIElement canvas, UIElement parent)
        {
            MainCanvas = canvas;
            this.parent = parent;
        }

        public void Drag_Button_MouseDown(object sender, ContactEventArgs e)
        {
            if (CanMove)
            {    // Capture to the ellipse.  
                ((BorderElement)parent).wr.CanResize = false;
                e.Contact.Capture((UIElement)sender);
                // Remember this contact if a contact has not been remembered already.  
                // This contact is then used to move the ellipse around.
                if (uielementControlContact == null)
                {
                    uielementControlContact = e.Contact;

                    // Remember where this contact took place.  
                    lastPoint = uielementControlContact.GetPosition(MainCanvas);
                }
                e.Handled = true;
            }
            // Mark this event as handled.  


        }

        public void Drag_Button_MouseMove(object sender, ContactEventArgs e)
        {
            if (CanMove && uielementControlContact != null)
            {
                // Get the current position of the contact.  
                Point currentTouchPoint = uielementControlContact.GetCenterPosition(MainCanvas);
                // Get the change between the controlling contact point and
                // the changed contact point.  
                double deltaX = currentTouchPoint.X - lastPoint.X;
                double deltaY = currentTouchPoint.Y - lastPoint.Y;

                // Get and then set a new top position and a new left position for the ellipse.  
                //double newTop = parent.RenderTransformOrigin.Y +deltaY;
                //double newLeft = parent.RenderTransformOrigin.X+ deltaX;

                //Canvas.SetTop(parent, newTop);

                if (lastPoint.X != 0 && lastPoint.Y != 0)
                {
                    ((FrameworkElement)parent).Margin = new Thickness(((FrameworkElement)parent).Margin.Left + deltaX, ((FrameworkElement)parent).Margin.Top + deltaY, ((FrameworkElement)parent).Margin.Right - deltaX, ((FrameworkElement)parent).Margin.Bottom - deltaY);
                    //((FrameworkElement)((BorderElement)parent).Content.Children[0]).Margin = new Thickness(((FrameworkElement)((BorderElement)parent).Content.Children[0]).Margin.Left + deltaX, ((FrameworkElement)((BorderElement)parent).Content.Children[0]).Margin.Top + deltaY, ((FrameworkElement)((BorderElement)parent).Content.Children[0]).Margin.Right - deltaX, ((FrameworkElement)((BorderElement)parent).Content.Children[0]).Margin.Bottom - deltaY);
                }
                // Forget the old contact point, and remember the new contact point.  
                lastPoint = currentTouchPoint;

                // Mark this event as handled.

                e.Handled = true;
            }

        }

        public void Drag_Button_MouseLeave(object sender, ContactEventArgs e)
        {
            // If this contact is the one that was remembered  
            if (CanMove)
            {
                // Forget about this contact.
               /* if (!itmove)
                {
                    if (uielementControlContact == null)
                        uielementControlContact = e.Contact;
                    //Drag_Button_MouseMove(sender, e);
                    Drag_Button_MouseMove(sender, e);
                }*/
                uielementControlContact = null;
                ((BorderElement)parent).wr.CanResize = true;

            }

            // Mark this event as handled.  
            e.Handled = true;

        }

        public void connectMouseHandlers(BorderElement element)
        {
            if (parent.GetHashCode() == element.GetHashCode())
            {
                element.bottomLeftSizeGrip.AddHandler(Contacts.ContactDownEvent, new ContactEventHandler(Drag_Button_MouseDown));
                element.bottomLeftSizeGrip.AddHandler(Contacts.ContactChangedEvent, new ContactEventHandler(Drag_Button_MouseMove));
                element.bottomLeftSizeGrip.AddHandler(Contacts.ContactLeaveEvent, new ContactEventHandler(Drag_Button_MouseLeave));
                element.topLeftSizeGrip.AddHandler(Contacts.ContactDownEvent, new ContactEventHandler(Drag_Button_MouseDown));
                element.topLeftSizeGrip.AddHandler(Contacts.ContactChangedEvent, new ContactEventHandler(Drag_Button_MouseMove));
                element.topLeftSizeGrip.AddHandler(Contacts.ContactLeaveEvent, new ContactEventHandler(Drag_Button_MouseLeave));

            }
        }

        public void deConnectMouseHandlers(BorderElement element)
        {
            if (parent.GetHashCode() == element.GetHashCode())
            {
                element.bottomLeftSizeGrip.RemoveHandler(Contacts.ContactDownEvent, new ContactEventHandler(Drag_Button_MouseDown));
                element.bottomLeftSizeGrip.RemoveHandler(Contacts.ContactChangedEvent, new ContactEventHandler(Drag_Button_MouseMove));
                element.bottomLeftSizeGrip.RemoveHandler(Contacts.ContactLeaveEvent, new ContactEventHandler(Drag_Button_MouseLeave));
                element.topLeftSizeGrip.RemoveHandler(Contacts.ContactDownEvent, new ContactEventHandler(Drag_Button_MouseDown));
                element.topLeftSizeGrip.RemoveHandler(Contacts.ContactChangedEvent, new ContactEventHandler(Drag_Button_MouseMove));
                element.topLeftSizeGrip.RemoveHandler(Contacts.ContactLeaveEvent, new ContactEventHandler(Drag_Button_MouseLeave));

            }
        }

    }
}